<?php
/**
 * @package		JYCMS
 * @subpackage	语言处理引擎
 * @version		$Id: class_language.php 8 2012-06-07 12:37:35Z htmambo@gmail.com $
 * @author		Hoping
 * @copyright	Copyright (C) 2009 Hoping Software Studio. All rights reserved.
 */

//保证此文件不被直接执行
defined( 'IN_JYCMS' ) or die( 'Direct Access to this location is not allowed.' );

class cmsLanguage {
	/** @var 逻辑型 如果设置为真，则高亮输出没有找到的字符串 */
	var $_debug = false;
	/** @var 字符串 官方语言的元素名称 */
	var $_name=null;
	/** @var 字符串 本地语言格式 */
	var $_locale=null;
	/** @var 字符串 语言的字符编码 */
	var $_iso=null;
	/** @var 字符串 语言的字符编码 */
	var $_isocode=null;
	/** @var 逻辑型 语言是否为从右到左输出 */
	var $_rtl=null;
	/** @var 字符串 当前加载的语言包 */
	var $_userLang=null;
	/** @var 字符串 确定语言的字符串 */
	var $_identifyer=null;
	/** @var 数组 翻译信息 */
	var $_strings=null;
	var $_option=null;

	/**
	* 构造信息
	*
	* @param 要加载的语言包 $userLang
	*
	*/
	function __construct($userLang = '') {
		$this->cmslanguage($userLang);
	}

	/**
	* 构造信息(兼容PHP4或以前版本)
	*
	* @param 要加载的语言包 $userLang
	*
	*/
	function cmslanguage( $userLang='' ) {
		$this->_strings = array();
		if( isset( $this->_locale ) ) {
			setlocale (LC_TIME, $this->_locale);
		}
		if(!$userLang) $userLang = 'zh-cn';
		$this->_userLang = $userLang;
	}

	/**
	 * 读取单个语言文件
	 */
	function load($option='') {
		$basePath = ROOT_PATH."/language/".$this->_userLang.'/';
		if(!is_dir($basePath)){
			dmkdir($basePath);
		}
		//加载前台默认语言包
		$this->_load($basePath.$this->_userLang.'.ini');
		if($option) {
			$option = strtolower($option);
			$o = substr($option, 0, 1);
			if($o == '@') {
				$option = substr($option, 1);
			} else {
				$this->_option = $option;
			}
			//加载前台指定应用的语言包
			$this->_load($basePath.$this->_userLang.'.'.$option.'.ini');
		}
	}

	/**
	 * Returns a reference to a language object
	 *
	 * This method must be invoked as:
	 * 		<pre>  $browser = &cmsLanguage::getInstance([$lang]);</pre>
	 *
	 * @access	public
	 * @param	string $lang  The language to use.
	 * @return	cmsLanguage  The Language object.
	 * @since	1.0
	 */
	function & getInstance($lang) {
		$instance = new cmsLanguage($lang);
		$reference = & $instance;
		return $reference;
	}

	/**
	* 翻译字符串
	*
	* @param 字符串 $string
	*/
	function _( $string, $jsSafe=false ) {
		$string = str_replace("=","#@#",trim($string));
		$string = str_replace("\t"," ",$string);
		$string = str_replace("\r"," ",$string);
		$string = str_replace("\n"," ",$string);
		$string = str_replace("  "," ",$string);
		$string = str_replace("  "," ",$string);
		$string = str_replace("  "," ",$string);
		$string = str_replace("  "," ",$string);
		$string = str_replace("  "," ",$string);
		$string = str_replace("  "," ",$string);
		$string = str_replace("  "," ",$string);
		$string = str_replace("  "," ",$string);
		$string = str_replace("  "," ",$string);
		$string = str_replace("  "," ",$string);
		$key = strtoupper( $string );
		$key = substr( $key, 0, 1) == '_' ? substr( $key, 1 ) : $key;
		if (isset( $this->_strings[$key] )) {
			$string = $this->_debug ? "&bull;".$this->_strings[$key]."&bull;" : $this->_strings[$key];
		} else {
			if( defined( $string ) ) {
				$string = $this->_debug ? "!!" .constant( $string ). "!!" : constant( $string );
			} else {
				$this->addstr($string);
				$string = $this->_debug ? "??$string??" : isset($this->_strings[$key])?$this->_strings[$key]:$string;
			}
		}
		if ($jsSafe) {
			$string = str_replace( "\n", '\\n', $string );
			$string = str_replace( '"', '&quot;', $string );
			$string = str_replace( '\'', '&#39;', $string );
		}
		$string = str_replace("#@#",'=',$string);
		return $string;
	}

	/**
	 * 通过 sprintf 来输出格式字符串
	 * @param 格式 The format string
	 * @param mixed Mixed number of arguments for the sprintf function
	 */
	function sprintf( $string ) {
		$args = func_get_args();
		if (count( $args ) > 0) {
			$args[0] = $this->_( $args[0] );
			return call_user_func_array( 'sprintf', $args );
		}
		return '';
	}

	/**
	 * Passes a string thru an printf
	 * @param format The format string
	 * @param mixed Mixed number of arguments for the sprintf function
	 */
	function printf( $string ) {
		$args = func_get_args();
		if (count( $args ) > 0) {
			$args[0] = $this->_( $args[0] );
			return call_user_func_array( 'printf', $args );
		}
		return '';
	}

	function parse( $txt, $process_sections = false, $asArray = false ) {
		if (is_string( $txt )) {
			$lines = explode( "\n", $txt );
		} else if (is_array( $txt )) {
			$lines = $txt;
		} else {
			$lines = array();
		}
		$obj = $asArray ? array() : new stdClass();
		$sec_name = '';
		$unparsed = 0;
		if (!$lines) {
			return $obj;
		}
		foreach ($lines as $line) {
			// ignore comments
			if ($line && $line[0] == ';') {
				continue;
			}
			$line = trim( $line );

			if ($line == '') {
				continue;
			}
			if ($line && $line[0] == '[' && $line[strlen($line) - 1] == ']') {
				$sec_name = substr( $line, 1, strlen($line) - 2 );
				if ($process_sections) {
					if ($asArray) {
						$obj[$sec_name] = array();
					} else {
						$obj->$sec_name = new stdClass();
					}
				}
			} else {
				if ($pos = strpos( $line, '=' )) {
					$property = strtoupper(trim( substr( $line, 0, $pos ) ));

					if (substr($property, 0, 1) == '"' && substr($property, -1) == '"') {
						$property = stripcslashes(substr($property,1,count($property) - 2));
					}
					$value = trim( substr( $line, $pos + 1 ) );
					if(strtolower(substr($value,0,6))=='array(') {
						eval("\$value = $value;");
					}
					if ($value == 'false') {
						$value = false;
					}
					if ($value == 'true') {
						$value = true;
					}
					if(is_string($value))
					if (substr( $value, 0, 1 ) == '"' && substr( $value, -1 ) == '"') {
						$value = stripcslashes( substr( $value, 1, count( $value ) - 2 ) );
					}

					if ($process_sections) {
						$value = str_replace( '\n', "\n", $value );
						if ($sec_name != '') {
							if ($asArray) {
								$obj[$sec_name][$property] = $value;
							} else {
								$obj->$sec_name->$property = $value;
							}
						} else {
							if ($asArray) {
								$obj[$property] = $value;
							} else {
								$obj->$property = $value;
							}
						}
					} else {
						$value = str_replace( '\n', "\n", $value );
						if ($asArray) {
							$obj[$property] = $value;
						} else {
							$obj->$property = $value;
						}
					}
				} else {
					if ($line && trim($line[0]) == ';') {
						continue;
					}
					if ($process_sections) {
						$property = '__invalid' . $unparsed++ . '__';
						if ($process_sections) {
							if ($sec_name != '') {
								if ($asArray) {
									$obj[$sec_name][$property] = trim($line);
								} else {
									$obj->$sec_name->$property = trim($line);
								}
							} else {
								if ($asArray) {
									$obj[$property] = trim($line);
								} else {
									$obj->$property = trim($line);
								}
							}
						} else {
							if ($asArray) {
								$obj[$property] = trim($line);
							} else {
								$obj->$property = trim($line);
							}
						}
					}
				}
			}
		}
		return $obj;
	}

	function _load( $filename ) {
		if (file_exists( $filename )) {
			if ($content = file_get_contents( $filename )) {
				if( $this->_identifyer === null ) {
					$this->_identifyer = basename( $filename, '.ini' );
				}
				$this->_strings = array_merge( $this->_strings, cmsLanguage::parse( $content, false, true ) );

				if (isset( $this->_strings['__NAME'] )) {
					$this->name( $this->_strings['__NAME'] );
				}
				if (isset( $this->_strings['__ISO'] )) {
					$this->iso( $this->_strings['__ISO'] );
				}
				if (isset( $this->_strings['__LOCALE'] )) {
					$this->locale( $this->_strings['__LOCALE'] );
				}
				if (isset( $this->_strings['__ISOCODE'] )) {
					$this->isoCode( $this->_strings['__ISOCODE'] );
				}
				if (isset( $this->_strings['__RTL'] )) {
					$this->rtl( $this->_strings['__RTL'] );
				}

				return true;
			}
		} else {
			$var="# JYCMS Language file\r\n# Created on ".date("Y-m-d, H:i")."\r\n\r\n";
			$this->write($filename,$var);
		}
		return false;
	}

	function addstr($str, $v = '') {
		if(!$str) return;
		if($str=='') return;
		$str = str_replace("\n", '\n', $str);
		$v = str_replace("\n", '\n', $v);
		$option = $this->_option;
		$basePath = ROOT_PATH."/language/".$this->_userLang.'/';
		$prefix = $option?'.'.$option:'';
		$filename = $basePath . $this->_userLang . $prefix . '.ini';

		if (!file_exists( $filename )) {
			$var="# JYCMS Language file\r\n# Created on ".date("Y-m-d, H:i")."\r\n\r\n";
			$this->write($filename,$var);
		}
		$tstr = $str;
		if($v) {
			$tstr = $v;
		}
		$str = str_replace('=', '#@#',  strtoupper($str));

		$var= $str . "=" . $tstr."\r\n";
		$this->write($filename,$var,'a');
		$this->load($option);
	}

	/**
	* Getter for Name
	* @param string An optional value
	* @return string Official name element of the language
	*/
	function name( $value=null ) {
		return $value !== null ? $this->_name = $value : $this->_name;
	}

	/**
	* Getter for ISO
	* @param string An optional value
	* @return string ISO charset for the html files
	*/
	function iso( $value=null ) {
		return $value !== null ? $this->_iso = $value : $this->_iso;
	}

	function isoCode( $value=null ) {
		return $value !== null ? $this->_isocode = $value : $this->_isocode;
	}

	function locale( $value=null ) {
		return $value !== null ? $this->_locale = $value : $this->_locale;
	}

	function rtl( $value=null ) {
		return $value !== null ? $this->_rtl = $value : $this->_rtl;
	}

	function debug( $value=null ) {
		return $value !== null ? $this->_debug = $value : $this->_debug;
	}

	/**
	 * Determines is a key exists
	 */
	function hasKey( $key ) {
		if(strpos($key, '=')) $key = str_replace('=', '#@#', $key);
		return isset( $this->_strings[strtoupper( $key )] );
	}

	function write($filename,$data,$method="wb") {
		$handle = @ fopen($filename,$method);
		if (false == $handle)return false;
		flock($handle,LOCK_EX);
		if (!@fwrite($handle,$data))return false;
		fclose($handle);
		return true;
	}
}
/**
 * 转换参数为字符串
 *
 * @param anytype $data 要转换的数据，目前主要是针对数组、对象
 * @return string 转换后的数据，主要用来进行错误报告的处理
 */
function anytypetostring($data='') {
	if($data) {
		if(is_string($data)) {
			return $data;
		} else {
			$data = str_replace(array("\r", "\n"),'',var_export($data, true));
			$data = str_replace('array (  ', 'ARRAY(', $data);
			return $data;
		}
	} else {
		return '{EMPTY}';
	}
}
